﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Game_Engine
{
    public class TerrainCollider : Collider
    {
        public TerrainRenderer Terrain
        {
            get;
            set;
        }

        public TerrainCollider(TerrainRenderer t)
        {
            Terrain = t;
            Name = "Terrain Collider";
        }

        //For a sphere collider
        public override bool Collides(Collider collider, out Vector3 normal)
        {
            normal = Vector3.Zero;
            if (collider is SphereCollider)
            {
                SphereCollider sc = collider as SphereCollider;
                Vector3 colliderPosition = sc.Transform.Position;

                //First order of business is finding out if we are even within the bounds of the terrain
                if ((colliderPosition.X < Terrain.Size.X / 2 && colliderPosition.X > -Terrain.Size.X / 2) &&
                    (colliderPosition.Z < Terrain.Size.Y / 2 && colliderPosition.Z > -Terrain.Size.Y / 2))
                {
                    //And if so use X-Y coordinates of offending collider to determine terrain height at that position
                    //Our GetHeight() method works under the assumption of texture coordinates however [0, 1]. So, we must 
                    //adjust the player position to suit this. We shift to the new range and take a ratio:
                    colliderPosition.X = (colliderPosition.X + Terrain.Size.X/2) / Terrain.Size.X;
                    colliderPosition.Z = (colliderPosition.Z + Terrain.Size.Y/2) / Terrain.Size.Y;
                    //Get the height at the new points
                    float height = Terrain.GetHeight(new Vector2(colliderPosition.X, colliderPosition.Z));
                    //Making sure to adjust for how high we've scaled the terrain to be
                    height *= Host.Transform.LocalScale.Y;
                    //Console.WriteLine(Host.Transform.Position.Y + height);
                    //Console.WriteLine(colliderPosition.Y);
                    //With height in hand we can use the collider's Y position to determine collision.
                    float extrusionDistance = Math.Abs(Host.Transform.Position.Y + height - colliderPosition.Y);
                    if (extrusionDistance < sc.Radius)
                    {
                        //We must access the normal map through the material and use the texified position coordinates to find a normal
                        normal = Terrain.Normals[(int)(colliderPosition.X * colliderPosition.Z * Terrain.Material.Texture.Width * Terrain.Material.Texture.Height)];
                        //We want to make sure the offending sphere is always sitting on top of or is only touching the terrain with its outermost side 
                        //We use this calculation to find how far to push the sphere out of the terrain (since a collision is defined as the sphere being inside it)
                        extrusionDistance = sc.Radius - extrusionDistance;
                        normal *= extrusionDistance;
                        return true;
                    }
                }  
            }
            return base.Collides(collider, out normal);
        }

        public override float? Intersects(Ray ray)
        {
            return base.Intersects(ray);
        }
    }
}
